﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed

#pragma once

#include "IGeometry.h"
#include "GcmpApiDeclaration.h"
#include "Box2d.h"

namespace gcmp
{
    class ICurve2d;
    class Vector2d;

    /// \brief 多段线（二维）
    ///
    /// 由收尾相连的二维曲线组成，可以不封闭
    class IPolyCurve : public IGeometry
    {
        DEFINE_CAST_DERIVED(gcmp::IPolyCurve, gcmp::IGeometry);
    public:
        /// \brief  创建一个空的多段线(不包含任何线)
        /// \return  多段线(不包含任何线)
        GCMP_GEOMETRY_INTERFACE_EXPORT static OwnerPtr<IPolyCurve> Create();

        /// \brief  创建一个多段线
        /// \param profilePoints    顺序点
        /// \return  多段线
        GCMP_GEOMETRY_INTERFACE_EXPORT static OwnerPtr<IPolyCurve> Create(const std::vector<Vector2d>& profilePoints);

        /// \brief  创建一个多段线
        /// \param  profileCurve2ds    顺序线段
        /// \return  多段线
        GCMP_GEOMETRY_INTERFACE_EXPORT static OwnerPtr<IPolyCurve> Create(const std::vector< OwnerPtr<ICurve2d> >& profileCurve2ds);

    public:
        /// \brief   获取二维包围盒
        /// \return  二维包围盒
        virtual Box2d GetBox2d() const = 0;

        /// \brief  获取多段线中曲线的数量
        /// \brief  曲线的数量
        virtual int GetCurveCount()const = 0;

        /// \brief  在多段线的首位置添加曲线
        /// \param opICurve    二维曲线
        /// \return  添加曲线后多段线中曲线首尾相连且封闭返回true，否则返回false
        virtual bool AddFrontCurve(OwnerPtr<ICurve2d> opICurve) = 0;

        /// \brief  在多段线的末尾添加曲线
        /// \param opICurve    二维曲线
        /// \return  添加曲线后多段线中曲线首尾相连且封闭返回true，否则返回false
        virtual bool AddBackCurve(OwnerPtr<ICurve2d> opICurve) = 0;

        /// \brief  删除首位置的曲线
        /// \return  删除首位置的曲线且封闭返回true，否则返回false
        virtual bool DeleteFrontCurve () = 0;

        /// \brief  删除尾位置的曲线
        /// \return  删除尾位置的曲线且封闭返回true，否则返回false
        virtual bool DeleteBackCurve() = 0;

        /// \brief 在多段线的起始和终止位置之间替换曲线
        /// \param begin      替换的起始位置
        /// \param end      替换的终止位置
        /// \param opICurve      多段线（二维）
        /// \return  替换曲线且合法返回true，否则返回false
        virtual bool ReplaceCurve(int begin, int end, OwnerPtr<ICurve2d> opICurve) = 0;

        /// \brief 在多段线的起始和终止位置之间替换曲线
        /// \param begin      替换的起始位置
        /// \param end      替换的终止位置
        /// \param opIPolyCurve      多段线（二维）
        /// \return  替换曲线且合法返回true，否则返回false
        virtual bool ReplaceCurve(int begin, int end, OwnerPtr<IPolyCurve> opIPolyCurve) = 0;

        /// \brief  在多段线的某个位置替换曲线
        /// \param index      替换的位置
        /// \param opICurve      二维曲线
        /// \return  替换曲线且合法返回true，否则返回false
        virtual bool ReplaceCurve(int index, OwnerPtr<ICurve2d> opICurve) = 0;

        /// \brief  在多段线的某个位置替换曲线
        /// \param index      替换的位置
        /// \param opIPolyCurve      多段线（二维）
        /// \return  替换曲线且合法返回true，否则返回false
        virtual bool ReplaceCurve(int index, OwnerPtr<IPolyCurve> opIPolyCurve) = 0;

        /// \brief  获取指定索引处的二维曲线（拷贝实现）
        /// \param index    索引
        /// \return  索引在二维边链表范围内返回拷贝后的二维边，否则返回空
        virtual OwnerPtr<ICurve2d> GetCurve(int index)const = 0;

        /// \brief  将多段线中的所有边反向
        /// \return   成功返回true,否则返回false(默认返回true)
        virtual bool Reverse() = 0;

        /// \brief   按顺序获取多段线中所有的曲线（拷贝实现）
        /// \param  curve2dlist 多段线中所有的曲线的链表
        /// \return  成功返回true,否则返回false(默认返回true)
        virtual bool GetAllCurves(std::vector<OwnerPtr<ICurve2d>>& curve2dlist) const = 0;

        /// \brief  判断多段线是否封闭
        /// \return 封闭返回true，否则返回false
        virtual bool IsClosed() const = 0;

        /// \brief  判断多段线是否为逆时针
        /// \return 逆时针返回true，否则返回false
        virtual bool IsAnticlockwise() const = 0;

        /// \brief  判断多段线是否合法（合法性检查包含：多段线首尾相连、多段线无自交）
        /// \return 合法返回true，否则返回false
        virtual bool IsValid() const = 0;

        /// \brief  判断多段线是否严格合法，比较慢，甚调
        /// \return 严格合法返回true，否则返回false
        virtual bool IsStrictlyValid() const = 0;


    public:
        /// \brief  判断多段线是否是整圆
        /// \return true: 是整圆，false: 非整圆
        virtual bool IsCircle() const = 0;

        /// \brief  判断多段线是否是整椭圆
        /// \return 整椭圆返回true，否则返回false
        virtual bool IsEllipse() const = 0;
        
        /// \brief  判断多段线是否是矩形
        /// \return 矩形返回true，否则返回false
        virtual bool IsRectangle() const = 0;

        /// \brief  设置距离容差
        /// \param distanceEpsilon 距离容差
        /// \return  成功返回true，失败返回false
        virtual bool SetDistEpsilon(double dDistEpsilon) = 0;

        /// \brief  合并多段线中可以合并的边
        /// 
        /// 若多段线中相邻边端点间(当前曲线终点和下一条曲线的起始点之间)的距离小于设置的距离容差，且相邻边为同类型可合并的曲线，则进行合并；否则，不进行合并
        /// \param dDistEpsilon 距离容差，建议使用0.0001
        /// \param dAngleEpsilon 角度容差，距离误差的辅助参数，用于几何相切（相邻边端点处相切方向夹角需要小于这个角度）等方向角度过滤，建议使用0.00005
        /// \return  若存在合并，返回true，否则返回false
        virtual bool MergeEdges(double dDistEpsilon, double dAngleEpsilon) = 0;

        /// \brief  根据给定的容差进行修补，删除小边，保证在容差dDistEpsilon下连接
        /// 
        /// \param dDistEpsilon 删除短边小于dDistEpsilon的边
        /// \return  是否修复，修复返回true，否则返回false
        virtual bool Repair(double dDistEpsilon) = 0;

        /// \brief  在多段线的末尾添加曲线
        /// \param pICurve    二维曲线
        /// \return  添加曲线后多段线中曲线首尾相连且封闭返回true，否则返回false
        GCMP_OBSOLETE_API(2020 / 10 / 30, IPolyCurve::AddCurve(OwnerPtr<ICurve2d>)) virtual bool AddCurveByClone(const ICurve2d* pICurve) = 0;

        /// \brief  在多段线中指定位置插入曲线
        /// \param index      插入的位置
        /// \param pICurve    二维曲线
        /// \return  插入曲线后多段线中曲线首尾相连且封闭返回true，否则返回false
        GCMP_OBSOLETE_API(2020 / 10 / 30, IPolyCurve::InsertCurve(int, OwnerPtr<ICurve2d>)) virtual bool InsertCurveByClone(int index, const ICurve2d* pICurve) = 0;

    public:
        virtual ~IPolyCurve() {};
    };
}
